#include <include/stdio.h>
#include <include/pic.h>
#include <include/x86.h>
#include <include/memlayout.h>
#include <include/trap.h>

#define NR_IRQ	16
irq_handler irq_table[NR_IRQ];
// Current IRQ mask.
// Initial IRQ mask has interrupt 2 enabled (for slave 8259A).
static uint16_t irq_mask_8259A=0xFFFF&~(1<<CASCADE_IRQ);

// return the trap description from a trap number.
static const char *
irqname(int irq)
{
	static const char * const irqnames[] = {
		"IRQ0: Timer && Clock",
		"IRQ1: Keyboard",
		"IRQ2: Connect to Slave 8259A",
		"IRQ3: Serial Port 2",
		"IRQ4: Serial Port 1",
		"IRQ5: LPT2",
		"IRQ6: Floppy",
		"IRQ7: LPT2",
		"IRQ8: Real Time Clock",
		"IRQ9: Redirect to IRQ2",
		"IRQ10: reserve",
		"IRQ11: reserve",
		"IRQ12: PS/2 mouse",
		"IRQ13: FPU exception",
		"IRQ14: AT winchester",
		"IRQ15: reserve",
	};
	if (irq >=0 && irq<NR_IRQ)
		return irqnames[irq];
	return "(unknown trap)";
}
static void
spurious_irq(struct Trapframe *tf)
{
	int irq_no=tf->tf_trapno-INT_VECTOR_IRQ0;
	cprintf("%s, #%d\n",irqname(tf->tf_trapno-INT_VECTOR_IRQ0),tf->tf_trapno);
	if (irq_no>=8) {
			outb(INT_S_CTL,EOI);
	}
	outb(INT_M_CTL,EOI);
}
/*
 *init the 8259A
 */
void
pic_init()
{
	// Master 8259, ICW1.
	outb(INT_M_CTL,	0x11);

	// Slave  8259, ICW1.
	outb(INT_S_CTL,	0x11);

	// Master 8259, ICW2. set the master's entry 0x20
	outb(INT_M_CTLMASK,	INT_VECTOR_IRQ0);

	// Slave  8259, ICW2.set the slave's entry 0x28
	outb(INT_S_CTLMASK,	INT_VECTOR_IRQ8);

	// Master 8259, ICW3. the irq2 is connected to the slave...
	outb(INT_M_CTLMASK,	0x4);

	// Slave  8259, ICW3. correspond to the master's irq2..
	outb(INT_S_CTLMASK,	0x2);

	// Master 8259, ICW4.
	outb(INT_M_CTLMASK,	0x1);

	// Slave  8259, ICW4.
	outb(INT_S_CTLMASK,	0x1);

	outb(INT_M_CTLMASK,(char)irq_mask_8259A);
	outb(INT_S_CTLMASK,(char)(irq_mask_8259A>>8));

	// initial all the irq handler to spuriours_irq..
	int i;
	for (i=0;i<NR_IRQ;i++)
		irq_table[i]=spurious_irq;
}
void
enable_irq(int irq)
{
	uint8_t mask;
	if (irq<0 || irq >=16)
		return;
	if (irq<8) {
		mask=inb(INT_M_CTLMASK);
		mask&=~(1<<irq);
		outb(INT_M_CTLMASK,mask);
	}
	else {
		mask=inb(INT_S_CTLMASK);
		mask&=~(1<<(irq-8));
		outb(INT_S_CTLMASK,mask);
	}
}
void
disable_irq(int irq)
{
	uint8_t mask;
	if (irq<0 || irq >=16)
		return;
	if (irq<8) {
		mask=inb(INT_M_CTLMASK);
		mask|=(1<<irq);
		outb(INT_M_CTLMASK,mask);
	}
	else {
		mask=inb(INT_S_CTLMASK);
		mask|=(1<<(irq-8));
		outb(INT_S_CTLMASK,mask);
	}
}
void
set_irq_handler(int irq,irq_handler handler)
{
	disable_irq(irq);
	irq_table[irq]=handler;
}
